﻿using UnityEditor;
using UnityEngine;
using System;

namespace RootMotion
{
    
    [CustomPropertyDrawer(typeof(ShowIfAttribute))]
    public class ShowIfPropertyDrawer : PropertyDrawer
    {
        protected ShowIfAttribute showIfAttribute;
        protected SerializedProperty prop;
        
        public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
        {
            if (!Show(property) && showIfAttribute.mode == ShowIfMode.Hidden) return -EditorGUIUtility.standardVerticalSpacing;

            return EditorGUI.GetPropertyHeight(property, label);
        }

        protected bool Show(SerializedProperty property)
        {
            showIfAttribute = attribute as ShowIfAttribute;

            var path = property.propertyPath.Contains(".") ? System.IO.Path.ChangeExtension(property.propertyPath, showIfAttribute.propName) : showIfAttribute.propName;

            prop = property.serializedObject.FindProperty(path);
            if (prop == null) return true;
            
            switch(prop.propertyType)
            {
                case SerializedPropertyType.Enum:
                    return prop.enumValueIndex.Equals((int)showIfAttribute.propValue);
                case SerializedPropertyType.Boolean:
                    return prop.boolValue.Equals(showIfAttribute.propValue);
                case SerializedPropertyType.Float:
                    return prop.floatValue > (float)showIfAttribute.propValue && prop.floatValue < (float)showIfAttribute.otherPropValue;
                case SerializedPropertyType.LayerMask:
                    return prop.intValue != 0;
                case SerializedPropertyType.String:
                    return prop.stringValue != string.Empty && prop.stringValue != "";
                case SerializedPropertyType.Vector2:
                    float sqrMag2 = prop.vector2Value.sqrMagnitude;
                    return sqrMag2 > (float)showIfAttribute.propValue && sqrMag2 < (float)showIfAttribute.otherPropValue;
                case SerializedPropertyType.Vector3:
                    float sqrMag3 = prop.vector3Value.sqrMagnitude;
                    return sqrMag3 > (float)showIfAttribute.propValue && sqrMag3 < (float)showIfAttribute.otherPropValue;
                case SerializedPropertyType.Vector4:
                    float sqrMag4 = prop.vector4Value.sqrMagnitude;
                    return sqrMag4 > (float)showIfAttribute.propValue && sqrMag4 < (float)showIfAttribute.otherPropValue;
                case SerializedPropertyType.ObjectReference:
                    return prop.objectReferenceValue != null;
                default:
                    Debug.LogError("Unsupported ShowIf property type: " + prop.propertyType);
                    return true;
            }
        }

        public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
        {
            showIfAttribute = attribute as ShowIfAttribute;

            EditorGUI.BeginProperty(position, label, property);

            if (Show(property))
            {
                if (showIfAttribute.indent) EditorGUI.indentLevel++;
                Draw(position, property, attribute, label);
                if (showIfAttribute.indent) EditorGUI.indentLevel--;
            }
            else if (showIfAttribute.mode == ShowIfMode.Disabled)
            {
                if (showIfAttribute.indent) EditorGUI.indentLevel++;
                GUI.enabled = false;
                Draw(position, property, attribute, label);
                GUI.enabled = true;
                if (showIfAttribute.indent) EditorGUI.indentLevel--;
            }

            EditorGUI.EndProperty();
        }

        protected virtual void Draw(Rect position, SerializedProperty property, PropertyAttribute attribute, GUIContent label)
        {
            
            EditorGUI.PropertyField(position, property, label, true);   
        }
    }

    [CustomPropertyDrawer(typeof(ShowRangeIfAttribute))]
    public class ShowRangeIfPropertyDrawer : ShowIfPropertyDrawer
    {
        protected override void Draw(Rect position, SerializedProperty property, PropertyAttribute attribute, GUIContent label)
        {
            ShowRangeIfAttribute range = attribute as ShowRangeIfAttribute;

            if (property.propertyType == SerializedPropertyType.Float)
                EditorGUI.Slider(position, property, range.min, range.max, label);
            else if (property.propertyType == SerializedPropertyType.Integer)
                EditorGUI.IntSlider(position, property, Convert.ToInt32(range.min), Convert.ToInt32(range.max), label);
            else
                EditorGUI.LabelField(position, label.text, "Use Range with float or int.");
        }
    }

    // Custom drawer for the LargeHeader attribute
    [CustomPropertyDrawer(typeof(ShowLargeHeaderIf))]
    public class ShowLargeHeaderIfDrawer : ShowIfPropertyDrawer
    {
        public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
        {
            if (!Show(property) && showIfAttribute.mode == ShowIfMode.Hidden) return -EditorGUIUtility.standardVerticalSpacing;

            return base.GetPropertyHeight(property, label) * 2f;
        }

        // Override the GUI drawing for this attribute
        protected override void Draw(Rect position, SerializedProperty property, PropertyAttribute attribute, GUIContent label)
        {
            var largeHeader = (ShowLargeHeaderIf)attribute;
            LargeHeaderDrawer.Draw(position, largeHeader.name, largeHeader.color);
        }
    }

    // Custom drawer for the LargeHeader attribute
    [CustomPropertyDrawer(typeof(LargeHeader))]
    public class LargeHeaderDrawer : DecoratorDrawer
    {
        // Get the height of the element
        public override float GetHeight()
        {
            return base.GetHeight() * 2f;
        }

        // Override the GUI drawing for this attribute
        public override void OnGUI(Rect position)
        {
            var largeHeader = (LargeHeader)attribute;
            Draw(position, largeHeader.name, largeHeader.color);
        }

        public static void Draw(Rect position, string name, string color)
        {
            // Get the color the line should be
            Color c = Color.white;
            switch (color.ToString().ToLower())
            {
                case "white": c = Color.white; break;
                case "red": c = Color.red; break;
                case "blue": c = Color.blue; break;
                case "green": c = Color.green; break;
                case "gray": c = Color.gray; break;
                case "grey": c = Color.grey; break;
                case "black": c = Color.black; break;
            }

            c *= 0.7f;

           var style = new GUIStyle(GUI.skin.label);
            style.fontSize = 16;
            style.fontStyle = FontStyle.Normal;
            style.alignment = TextAnchor.LowerLeft;
            GUI.color = c;

            Rect labelRect = position;
            EditorGUI.LabelField(labelRect, name, style);

            GUI.color = Color.white;
        }
    }
}
